#include "PreCompiled.h"
#include "view3DInventorViewer.h"
#include "NavigationStyle.h"
#include "UnifiedSelection.h"
#include "Camera.h"
extern "C" void InitCustomPlayerContextEx();
using namespace Gui;
view3DInventorViewer::view3DInventorViewer(QWidget* parent)
:QFrame(parent),m_RasterizerFamily(CKRST_DIRECTX)
,m_RasterizerFlags(CKRST_SPECIFICCAPS_HARDWARE|CKRST_SPECIFICCAPS_DX9)
,m_FullscreenWidth(640),m_FullscreenHeight(480),m_FullscreenBpp(32),navigation(0)
,selectionRoot(0),mPressFlag(false)
{
//  	watch.start();
//  	ticker.start(20, this);

// enable mouse tracking when moving even if no buttons are pressed
	//setMouseTracking(true);

	setAttribute(Qt::WA_PaintOnScreen, true);
 	QTimer *timer = new QTimer(this);
 	connect(timer, SIGNAL(timeout()), this, SLOT(update()));
 	timer->start(20);

	initializeRender(this);

	navigation = new CADNavigationStyle;
	navigation->setViewer(this);

    setFocusPolicy(Qt::StrongFocus);

	setPopupMenuEnabled(true);

	selectionRoot = new UnifiedSelection();

	CameraRoot* ca = new FreeCamera("freecamera");
	CameraManager::Instance()->setActiveCamera(ca);

	

}

view3DInventorViewer::~view3DInventorViewer(void)
{
	delete navigation;
	destructRender();
}
  QPaintEngine *view3DInventorViewer::paintEngine() const
  {
  	return NULL;
  }
void view3DInventorViewer::paintEvent(QPaintEvent * e)
{
 	if(updatesEnabled())
 	{
        process();
 	}
}
bool view3DInventorViewer::event(QEvent* e)
{
	if(navigation)
		navigation->processEvent(e);

	return QWidget::event(e);
}
void view3DInventorViewer::setPopupMenuEnabled(const bool on)
{
    navigation->setPopupMenuEnabled(on);
}
bool view3DInventorViewer::isPopupMenuEnabled(void)const
{
   return navigation->isPopupMenuEnabled();
}

VxRect&  view3DInventorViewer::getViewRect()
{
	VxRect rect;
	if(m_RenderContext)
	m_RenderContext->GetViewRect(rect);
	return  rect;
}
void view3DInventorViewer::resizeEvent(QResizeEvent* e)
{
	resizeRenderView(parentWidget()->width(),parentWidget()->height());
}
void view3DInventorViewer::timerEvent(QTimerEvent * e)
{
   	  // process();	
}

void view3DInventorViewer::OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
									Gui::SelectionSingleton::MessageType Reason)
{

}
void view3DInventorViewer::processEvent(QEvent* e)
{

}
void view3DInventorViewer::setDocument(Document_Gui* pDocument)
{
   selectionRoot->pcDocument = pDocument;
}

void view3DInventorViewer::processSelection(int smode)
{
	if(selectionRoot)
	 selectionRoot->processSelection(smode);
}

bool view3DInventorViewer::process()
{

	if (!m_CKContext || !m_CKContext->IsPlaying()) {
		Sleep(10);
		return TRUE;
	}

	float beforeRender	= 0;
	float beforeProcess	= 0;
	// retrieve the time to wait in milliseconds to perfom a rendering or a process loop
	// so that the time manager limits are respected.
	m_TimeManager->GetTimeToWaitForLimits(beforeRender,beforeProcess);

	if (beforeProcess<=0) {
		// ok to process
		m_TimeManager->ResetChronos(FALSE,TRUE);
		m_CKContext->Process();
	}

	if (beforeRender<=0) {
		// ok to render
		m_TimeManager->ResetChronos(TRUE,FALSE);
		m_RenderContext->Render();
	}

	
   Processkeyboard();
	CameraManager::Instance()->updateCamera();

	return TRUE;
}
void view3DInventorViewer::resizeRenderView(int width,int height)
{
    if(!m_RenderContext)
		return;
	if(width <=0 || height <=0)
		return;

	m_RenderContext->Resize(0,0,width,height);


}
void view3DInventorViewer::destructRender()
{
	try {
		if (!m_CKContext) {
			return;
		}

		// clear the CK context
		m_CKContext->Reset();
		m_CKContext->ClearAll();

		// destroy the render engine
		if (m_RenderManager && m_RenderContext) {
			m_RenderManager->DestroyRenderContext(m_RenderContext);
		}
		m_RenderContext = NULL;

		// close the ck context
		CKCloseContext(m_CKContext);

		m_CKContext = NULL;

		// shutdown all
		CKShutdown();

		m_CKContext = NULL;
	} catch(...) {
	}
}
BOOL view3DInventorViewer::initializeRender(QWidget* iRenderWindow)
{
	InitCustomPlayerContextEx();
	_CKStartUp();

	CKPluginManager* pluginManager = CKGetPluginManager();

	if (!_InitPlugins(*pluginManager))
		return FALSE;

	int renderEngine = _InitRenderEngines(*pluginManager);
	if (renderEngine==-1)
		return FALSE;

	CKERROR res = CKCreateContext(&m_CKContext,iRenderWindow->winId(),0);
	if (res!=CK_OK)
		return FALSE;

	m_TimeManager = m_CKContext->GetTimeManager();
	if(!m_TimeManager)
		return FALSE;

	m_RenderManager		= m_CKContext->GetRenderManager();
	if(!m_RenderManager)
		return FALSE;

	if (!_InitDriver())
		return FALSE;

	m_RenderContext = m_RenderManager->CreateRenderContext(iRenderWindow->winId(),m_Driver,0,FALSE);
   if(!m_RenderContext)
	  return FALSE;

  	m_InputManager		= (CKInputManager*)m_CKContext->GetManagerByGuid(INPUT_MANAGER_GUID);
	if(!m_InputManager)
		return FALSE;


   int w = iRenderWindow->width();
   m_RenderContext->Resize(0,0,iRenderWindow->width(),iRenderWindow->height());

   if(_Load("furniture.cmo") != CK_OK)
	   return FALSE;

   m_RenderContext->Clear();
   m_RenderContext->BackToFront();
   m_RenderContext->Clear();

   if(!_FinishLoad())
	   return FALSE;

   m_CKContext->Reset();
   m_CKContext->Play();

   return TRUE;
}

BOOL view3DInventorViewer::_FinishLoad()
{
    m_Level = m_CKContext->GetCurrentLevel();
	if(!m_Level)
		return FALSE;

	m_Level->AddRenderContext(m_RenderContext,TRUE);

	m_CKContext->SetLastCmoLoaded("CustomPlayer.vmo");

	m_Level->LaunchScene(NULL);

	m_RenderContext->Render();

	return TRUE;
}

// ------------------------------ [4/18/2013 Administrator]

BOOL view3DInventorViewer::_Load(const char* fn)
{
  if(!fn || !(*fn) || strlen(fn)<=0)
  {
	  return FALSE;
  }

  CKFile* f = m_CKContext->CreateCKFile();
  XString resolvedfile = fn;
  {
	  CKPathManager *pm = m_CKContext->GetPathManager();	
	  if(pm) {
		  pm->ResolveFileName(resolvedfile,0);
	  }
  }

  DWORD res = CKERR_INVALIDFILE;
  res = f->OpenFile(resolvedfile.Str(),(CK_LOAD_FLAGS) (CK_LOAD_DEFAULT | CK_LOAD_CHECKDEPENDENCIES));
  if(res != CK_OK)
    return FALSE;

  CKPathSplitter ps(resolvedfile.Str());
  CKPathMaker mp(ps.GetDrive(),ps.GetDir(),NULL,NULL);
  if(strcmp(mp.GetFileName(),CKGetStartPath())){
	  CKPathManager *pm = m_CKContext->GetPathManager();
	  XString XStr = XString(mp.GetFileName());
	  pm->AddPath(BITMAP_PATH_IDX,XStr);
	  XStr = XString(mp.GetFileName());
	  pm->AddPath(DATA_PATH_IDX,XStr);
	  XStr = XString(mp.GetFileName());
	  pm->AddPath(SOUND_PATH_IDX,XStr);			
  }

  CKObjectArray *array = CreateCKObjectArray();	
  res = f->LoadFileData(array);	
  if(res != CK_OK) {
	  m_CKContext->DeleteCKFile(f);
	  DeleteCKObjectArray(array);
	  return res;
  }

  m_CKContext->DeleteCKFile(f);

  DeleteCKObjectArray(array);	

  return CK_OK;
}

BOOL view3DInventorViewer::_InitPlugins(CKPluginManager& iPluginManager)
{
	char szPath[_MAX_PATH];
	char PluginPath[_MAX_PATH];
	char RenderPath[_MAX_PATH];
	char BehaviorPath[_MAX_PATH];
	char ManagerPath[_MAX_PATH];

	VxGetModuleFileName(NULL,szPath,_MAX_PATH);
	CKPathSplitter ps(szPath);
	sprintf(PluginPath,"%s%s%s",ps.GetDrive(),ps.GetDir(),"Plugins");
	sprintf(RenderPath,"%s%s%s",ps.GetDrive(),ps.GetDir(),"RenderEngines");
	sprintf(ManagerPath,"%s%s%s",ps.GetDrive(),ps.GetDir(),"Managers");
	sprintf(BehaviorPath,"%s%s%s",ps.GetDrive(),ps.GetDir(),"BuildingBlocks");

	iPluginManager.ParsePlugins(RenderPath);
	iPluginManager.ParsePlugins(ManagerPath);
	iPluginManager.ParsePlugins(BehaviorPath);
	iPluginManager.ParsePlugins(PluginPath);

	return TRUE;
}
int	 view3DInventorViewer::_InitRenderEngines(CKPluginManager& iPluginManager)
{
	// here we look for the render engine (ck2_3d)
	int count = iPluginManager.GetPluginCount(CKPLUGIN_RENDERENGINE_DLL);
	for (int i=0;i<count;i++) {
		CKPluginEntry* desc = iPluginManager.GetPluginInfo(CKPLUGIN_RENDERENGINE_DLL,i); 
		CKPluginDll*   dll  = iPluginManager.GetPluginDllInfo(desc->m_PluginDllIndex); 
#if !defined(CUSTOM_PLAYER_STATIC)
		XDWORD pos = dll->m_DllFileName.RFind(DIRECTORY_SEP_CHAR);
		if (pos==XString::NOTFOUND)
			continue;
		XString str = dll->m_DllFileName.Substring(pos+1);
		if (strnicmp(str.CStr(),"ck2_3d",strlen("ck2_3d"))==0)
			return i;
#else
		if (dll->m_DllFileName.ICompare("ck2_3d")==0)
			return i;
#endif
	}

	return -1;
}
BOOL view3DInventorViewer::_InitDriver()
{
	int count = m_RenderManager->GetRenderDriverCount();
	int i = 0;

	// first, we try to get exactly what is required
	int checkFlags = eFamily | eDirectXVersion | eSoftware;
	for (i=0;i<count;++i) {
		VxDriverDesc* desc = m_RenderManager->GetRenderDriverDescription(i);
		if (!desc) {
			continue;
		}

		if (_CheckDriver(desc,checkFlags)) {
			m_Driver = i;
			_CheckFullscreenDisplayMode(TRUE);
			return TRUE;
		}
	}

	if (m_RasterizerFamily == CKRST_OPENGL) {
		return FALSE;
	}

	// if we did not find a driver,
	// we only check family and software flags
	checkFlags &= ~eDirectXVersion;
	for (i=0;i<count;++i) {
		VxDriverDesc* desc = m_RenderManager->GetRenderDriverDescription(i);
		if (!desc) {
			continue;
		}

		if (_CheckDriver(desc,checkFlags)) {
			m_Driver = i;
			_CheckFullscreenDisplayMode(TRUE);
			return TRUE;
		}
	}

	return FALSE;
}
BOOL view3DInventorViewer::_CheckDriver(VxDriverDesc* iDesc, int iFlags)
{
	// check the rasterizer family
	if (iFlags & eFamily) { 
		if (iDesc->Caps2D.Family!=CKRST_DIRECTX) {
			return FALSE;
		}
	}

	// test directx version
	if ( (iDesc->Caps2D.Family==CKRST_DIRECTX) && (iFlags & eDirectXVersion) ) {
		if ((iDesc->Caps3D.CKRasterizerSpecificCaps&0x00000f00UL)!=(m_RasterizerFlags&0x00000f00UL)) {
			return FALSE;
		}
	}

	// test hardware/software
	if (iFlags & eSoftware) {
		if (((int)iDesc->Caps3D.CKRasterizerSpecificCaps&CKRST_SPECIFICCAPS_SOFTWARE)!=(m_RasterizerFlags&CKRST_SPECIFICCAPS_SOFTWARE)) {
			return FALSE;
		}	
	}

	return TRUE;
}
BOOL view3DInventorViewer::_CheckFullscreenDisplayMode(BOOL iDoBest)
{
	VxDriverDesc* desc = m_RenderManager->GetRenderDriverDescription(m_Driver);

	// try to find the correct fullscreen display mode
	for (VxDisplayMode* displayMode=desc->DisplayModes.Begin();displayMode!=desc->DisplayModes.End();displayMode++) {
		if (displayMode->Width==m_FullscreenWidth	&& displayMode->Height==m_FullscreenHeight	&& displayMode->Bpp==m_FullscreenBpp)
		{
				m_FullscreenEnabled = TRUE;
				return TRUE;
		}
	}

	if (!iDoBest) {
		return FALSE;
	}

	
	return FALSE;
}


//////////////////////////////////////////////////////////////////////////



void view3DInventorViewer::keyPressEvent(QKeyEvent* e)
{
    if(e->isAutoRepeat())
	{
		e->ignore();
		return;

	}
  CameraManager::Instance()->keydown(e);

}
void view3DInventorViewer::keyReleaseEvent(QKeyEvent* e)
{
	if(e->isAutoRepeat())
	{
	      e->ignore();
		  return;
	}
  CameraManager::Instance()->keyup(e);
}
void view3DInventorViewer::mouseMoveEvent(QMouseEvent* e)
{
	CameraManager::Instance()->mousebuttonMove(e);
}
void view3DInventorViewer::mousePressEvent(QMouseEvent *e)
{
	CameraManager::Instance()->mousebuttonDown(e);
}
void  view3DInventorViewer::mouseReleaseEvent(QMouseEvent *e)
{
	CameraManager::Instance()->mousebuttonUp(e);
}

void view3DInventorViewer::Processkeyboard()
{

// 	if(m_InputManager->IsKeyDown(CKKEY_W))
// 		CameraManager::Instance()->wkeydown();
// 	else
// 		CameraManager::Instance()->wkeyup();

	
// 	CKDWORD key = 0;
// 	int keynum = m_InputManager->GetNumberOfKeyInBuffer();
// 	for (int i = 0; i < keynum; i++)
// 	{
// 		if(m_InputManager->GetKeyFromBuffer(i,key) == KEY_PRESSED)
// 		{
// 			CameraManager::Instance()->keydown(key);
// 		}
// 		if(m_InputManager->GetKeyFromBuffer(i,key) == KEY_RELEASED)
// 		{
// 			CameraManager::Instance()->keyup(key);
// 		}
// 	}
}